/*
 ============================================================================
 Name        : QueueTest.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include "omp.h"
#include "IList.h"
#include <math.h>
#include <string.h>
#include <unistd.h>

LIST q;
void test_1(int ops){
	unsigned short state[3];
	unsigned int seed = time(0) + (unsigned int) omp_get_thread_num();
	memcpy(state, &seed, sizeof(seed));

	int i,j;
	for (i = 0; i < ops; ++i){
		long ran = nrand48(state);
		ps_insert(&q, ran % (ops*2));
		for(j=0; j<1000;) j++;
		ps_remove(&q, ran % (ops*2));
		for(j=0; j<1000;) j++;
	}
}

void test_2(int ops, int p){
	unsigned short state[3];
	unsigned int seed = time(0) + (unsigned int) omp_get_thread_num();
	memcpy(state, &seed, sizeof(seed));

	int i,j;
	for (i = 0; i < ops; ++i){
		long ran = nrand48(state);
		if((ran % 100) <= p)
			ps_insert(&q, ran % (ops*2));
		else
			ps_remove(&q, ran % (ops*2));

		for(j=0; j<1000;) j++;
	}
}

void test_remove(int ops, int p){

	unsigned short state[3];
	unsigned int seed = time(0) + (unsigned int) omp_get_thread_num();
	memcpy(state, &seed, sizeof(seed));

	int e;
	int i = 0;
    for (; i < ops; ++i){
    	long ran = nrand48(state);
    	if((ran % 100) <= p)
    		ps_remove(&q, ran % (ops*2));
    	else
    		for(e=0;e<10000;++e);//busy wait
    }
}

void test_insert(int ops, int p){
	unsigned short state[3];
	unsigned int seed = time(0) + (unsigned int) omp_get_thread_num();
	memcpy(state, &seed, sizeof(seed));

	int e;
	int i = 0;
	for (; i < ops; ++i){
		long ran = nrand48(state);
		if((ran % 100) <= p)
			ps_insert(&q, ran % (ops*2));
		else
			for(e=0;e<10000;++e);//busy wait
	}
}

int main( int argc, char** argv) {

	struct timeval stime, etime;

	int workers = atoi(argv[1]);

	int add_percentage = atoi(argv[2]);
	int ops = atoi(argv[3]);

	init_list(&q);

	omp_set_nested(1);
	#pragma omp parallel num_threads(workers)
	{
		if(workers > 0)
			test_1(ops/workers);
		#pragma omp barrier
	}

	clear(&q);
	init_list(&q);
	if (gettimeofday(&stime, NULL)) {
		fprintf(stderr, "gettimeofday failed");
		exit(1);
	}

	#pragma omp parallel num_threads(workers)
	{
		if(workers > 0)
			test_1(ops/workers);
		#pragma omp barrier
	}

	if (gettimeofday(&etime, NULL)) {
		fprintf(stderr, "gettimeofday failed");
		exit(1);
	}

	double t = (etime.tv_sec - stime.tv_sec) + (etime.tv_usec - stime.tv_usec)/ 1000000.0;

	printf("test_1, workers:%d, add_percentage:%d, time(ms):%lf\n", workers, add_percentage, t);

	clear(&q);
	init_list(&q);
	test_2(1000, 100); /*warm up the list adding 1000 elements */
	/* int c = count(&q); */
	/*printf("count: %d\n", c);*/

	if (gettimeofday(&stime, NULL)) {
		fprintf(stderr, "gettimeofday failed");
		exit(1);
	}

	#pragma omp parallel num_threads(workers)
	{
		if(workers > 0)
			test_2(ops/workers, add_percentage);
		#pragma omp barrier
	}

	if (gettimeofday(&etime, NULL)) {
		fprintf(stderr, "gettimeofday failed");
		exit(1);
	}

	t = (etime.tv_sec - stime.tv_sec) + (etime.tv_usec - stime.tv_usec)/ 1000000.0;

	printf("test_2, workers:%d, add_percentage:%d, time(ms):%lf\n", workers, add_percentage, t);

	clear(&q);
	/* puts("Done!"); */
	return EXIT_SUCCESS;
}
